/*   Copyright © 2009 Mark Gil Torres
 *
 *   This file is part of mtoolkit.
 *
 *   mtoolkit is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   any later version.
 *
 *   mtoolkit is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with mtoolkit.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef MTA_ARITHMETIC_HPP
#define MTA_ARITHMETIC_HPP

#include <iostream>
#include <stack>

#include "../include/integer.h"
#include "../include/rational.h"
#include "../include/real.h"
#include "variant.hpp"

using namespace mt;
using namespace std;

/*
struct arithmetic_add {
  arithmetic_add(stack<Variant>& inStack) : myStack(inStack) {}
  void operator()(char const* str, char const* end) const {
    Variant x, y, z ;
    x = myStack.top();
    myStack.pop();
    y = myStack.top();
    myStack.pop();
    int dType1 = x.getDataType();
    int dType2 = y.getDataType();
    if (dType1 == dType2) {
      if (dType1 == 3) {
        Real a, b, c;
        a = y.getRValue();
        b = x.getRValue();
        c = a + b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      else if (dType1 == 2) {
        Rational a, b, c;
        a = y.getQValue();
        b = x.getQValue();
        c = a + b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
      else if (dType1 == 1) {
        Integer a, b, c;
        a = y.getZValue();
        b = x.getZValue();
        c = a + b;
        z.setZValue(c);
        myStack.push(z);
        cout<<": "<<c<<endl;
      }
    }
    else if (dType1 > dType2) {
      if (dType1 == 3) {
        Real a, b, c;
        if (dType2 == 2 ) {
          a = convertRfromQ(y.getQValue());
        }
        else if (dType2 == 1) {
          a = convertRfromZ(y.getZValue());
        }
        b = x.getRValue();
        c = a + b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      if (dType1 == 2) {
        Rational a, b, c;
        if (dType2 == 1) {
          a = convertQfromZ(y.getZValue());
        }
        b = x.getQValue();
        c = a + b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
    }
    else if (dType2 > dType1) {
      if (dType2 == 3) {
        Real a, b, c;
        if (dType1 == 2 ) {
          b = convertRfromQ(x.getQValue());
        }
        else if (dType1 == 1) {
          b = convertRfromZ(x.getZValue());
        }
        a = y.getRValue();
        c = a + b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      if (dType2 == 2) {
        Rational a, b, c;
        if (dType1 == 1) {
          b = convertQfromZ(x.getZValue());
        }
        a = y.getQValue();
        c = a + b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
    }
  }
  stack<Variant>& myStack;
};

struct arithmetic_minus {
  arithmetic_minus(stack<Variant>& inStack) : myStack(inStack) {}
  void operator()(char const* str, char const* end) const {
    Variant x, y, z ;
    x = myStack.top();
    myStack.pop();
    y = myStack.top();
    myStack.pop();
    int dType1 = x.getDataType();
    int dType2 = y.getDataType();
    if (dType1 == dType2) {
      if (dType1 == 3) {
        Real a, b, c;
        a = y.getRValue();
        b = x.getRValue();
        c = a - b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      else if (dType1 == 2) {
        Rational a, b, c;
        a = y.getQValue();
        b = x.getQValue();
        c = a - b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
      else if (dType1 == 1) {
        Integer a, b, c;
        a = y.getZValue();
        b = x.getZValue();
        c = a - b;
        z.setZValue(c);
        myStack.push(z);
        cout<<": "<<c<<endl;
      }
    }
    else if (dType1 > dType2) {
      if (dType1 == 3) {
        Real a, b, c;
        if (dType2 == 2 ) {
          a = convertRfromQ(y.getQValue());
        }
        else if (dType2 == 1) {
          a = convertRfromZ(y.getZValue());
        }
        b = x.getRValue();
        c = a - b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      if (dType1 == 2) {
        Rational a, b, c;
        if (dType2 == 1) {
          a = convertQfromZ(y.getZValue());
        }
        b = x.getQValue();
        c = a - b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
    }
    else if (dType2 > dType1) {
      if (dType2 == 3) {
        Real a, b, c;
        if (dType1 == 2 ) {
          b = convertRfromQ(x.getQValue());
        }
        else if (dType1 == 1) {
          b = convertRfromZ(x.getZValue());
        }
        a = y.getRValue();
        c = a - b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      if (dType2 == 2) {
        Rational a, b, c;
        if (dType1 == 1) {
          b = convertQfromZ(x.getZValue());
        }
        a = y.getQValue();
        c = a - b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
    }
  }
  stack<Variant>& myStack;
};

struct arithmetic_times {
  arithmetic_times(stack<Variant>& inStack) : myStack(inStack) {}
  void operator()(char const* str, char const* end) const {
    Variant x, y, z ;
    x = myStack.top();
    myStack.pop();
    y = myStack.top();
    myStack.pop();
    int dType1 = x.getDataType();
    int dType2 = y.getDataType();
    if (dType1 == dType2) {
      if (dType1 == 3) {
        Real a, b, c;
        a = y.getRValue();
        b = x.getRValue();
        c = a * b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      else if (dType1 == 2) {
        Rational a, b, c;
        a = y.getQValue();
        b = x.getQValue();
        c = a * b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
      else if (dType1 == 1) {
        Integer a, b, c;
        a = y.getZValue();
        b = x.getZValue();
        c = a * b;
        z.setZValue(c);
        myStack.push(z);
        cout<<": "<<c<<endl;
      }
    }
    else if (dType1 > dType2) {
      if (dType1 == 3) {
        Real a, b, c;
        if (dType2 == 2 ) {
          a = convertRfromQ(y.getQValue());
        }
        else if (dType2 == 1) {
          a = convertRfromZ(y.getZValue());
        }
        b = x.getRValue();
        c = a * b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      if (dType1 == 2) {
        Rational a, b, c;
        if (dType2 == 1) {
          a = convertQfromZ(y.getZValue());
        }
        b = x.getQValue();
        c = a * b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
    }
    else if (dType2 > dType1) {
      if (dType2 == 3) {
        Real a, b, c;
        if (dType1 == 2 ) {
          b = convertRfromQ(x.getQValue());
        }
        else if (dType1 == 1) {
          b = convertRfromZ(x.getZValue());
        }
        a = y.getRValue();
        c = a * b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      if (dType2 == 2) {
        Rational a, b, c;
        if (dType1 == 1) {
          b = convertQfromZ(x.getZValue());
        }
        a = y.getQValue();
        c = a * b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
    }
  }
  stack<Variant>& myStack;
};

struct arithmetic_div {
  arithmetic_div(stack<Variant>& inStack) : myStack(inStack) {}
  void operator()(char const* str, char const* end) const {
    Variant x, y, z ;
    x = myStack.top();
    myStack.pop();
    y = myStack.top();
    myStack.pop();
    int dType1 = x.getDataType();
    int dType2 = y.getDataType();
    if (dType1 == dType2) {
      if (dType1 == 3) {
        Real a, b, c;
        a = y.getRValue();
        b = x.getRValue();
        c = a / b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      else if (dType1 == 2) {
        Rational a, b, c;
        a = y.getQValue();
        b = x.getQValue();
        c = a / b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
      else if (dType1 == 1) {
        Integer a, b, c;
        a = y.getZValue();
        b = x.getZValue();
        c = a / b;
        z.setZValue(c);
        myStack.push(z);
        cout<<": "<<c<<endl;
      }
    }
    else if (dType1 > dType2) {
      if (dType1 == 3) {
        Real a, b, c;
        if (dType2 == 2 ) {
          a = convertRfromQ(y.getQValue());
        }
        else if (dType2 == 1) {
          a = convertRfromZ(y.getZValue());
        }
        b = x.getRValue();
        c = a / b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      if (dType1 == 2) {
        Rational a, b, c;
        if (dType2 == 1) {
          a = convertQfromZ(y.getZValue());
        }
        b = x.getQValue();
        c = a / b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
    }
    else if (dType2 > dType1) {
      if (dType2 == 3) {
        Real a, b, c;
        if (dType1 == 2 ) {
          b = convertRfromQ(x.getQValue());
        }
        else if (dType1 == 1) {
          b = convertRfromZ(x.getZValue());
        }
        a = y.getRValue();
        c = a / b;
        z.setRValue(c);
        myStack.push(z);
        cout.precision(20);
        cout<<": "<<c<<endl;
      }
      if (dType2 == 2) {
        Rational a, b, c;
        if (dType1 == 1) {
          b = convertQfromZ(x.getZValue());
        }
        a = y.getQValue();
        c = a / b;
        z.setQValue(c);
        myStack.push(z);
        if (c.getDenominator() == 1) cout<<": "<<c.getNumerator()<<endl;
        else cout<<": \\frac{"<<c.getNumerator()<<"}{"<<c.getDenominator()<<"}\n";
      }
    }

  }
  stack<Variant>& myStack;
};
*/

#endif
